﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.VisualStudio.Utilities;

namespace VsSpeakerCompanion
{
    /// <summary>
    /// Provides context information to the widgets
    /// </summary>
    public class Context
    {
        /// <summary>
        /// Gets the internal storage for the context properties.
        /// </summary>
        internal PropertyCollection Properties { get; private set; }

        /// <summary>
        /// The event is raised when a VS Speaker session is starting
        /// </summary>
        public event EventHandler SessionStarting;
        
        /// <summary>
        /// The event is raised when a VS Speaker was Started
        /// </summary>
        public event EventHandler SessionStarted;

        /// <summary>
        /// The event is raised when a VS Speaker session is ending
        /// </summary>
        public event EventHandler SessionEnding;

        /// <summary>
        /// The event is raised when a VS Speaker session was ended
        /// </summary>
        public event EventHandler SessionEnded;

        /// <summary>
        /// Gets the VS Speaker settings. The settings are serialized between VS Speaker sessions.
        /// </summary>
        public Settings Settings { get; private set; }

        /// <summary>
        /// Gets the VS Speaker shared settings. Every setting is loaded/saved every time so these settings are useful for consumption from different instances of VS Speaker.
        /// </summary>
        public Settings SharedSettings { get; private set; }

        /// <summary>
        /// Returns true if the VS Speaker session is already started
        /// </summary>
        public bool IsSessionStarted { get; private set; }
        
        internal Context()
        {
            this.Properties = new PropertyCollection();
            this.Settings = new Settings();
            this.SharedSettings = new SharedSettings();
        }

        /// <summary>
        /// Returns true if the context contains a property with the specified key
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public bool ContainsProperty(object key)
        {
            return this.Properties.ContainsProperty(key);
        }

        /// <summary>
        /// Returns the property value of type T
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetProperty<T>()
        {
            return this.GetProperty<T>(typeof(T));
        }

        /// <summary>
        /// Returns the property value for the specified key.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <returns></returns>
        public T GetProperty<T>(object key)
        {
            if (this.Properties.ContainsProperty(key))
            {
                return (T)this.Properties.GetProperty<T>(key);
            }

            return default(T);
        }

        /// <summary>
        /// Adds a property value to the context.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        public void AddProperty<T>(T value)
        {
            this.AddProperty<T>(typeof(T), value);
        }

        /// <summary>
        /// Adds a property value to the context.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="value"></param>
        public void AddProperty<T>(object key, T value)
        {
            if (this.Properties.ContainsProperty(key))
            {
                this.Properties.RemoveProperty(key);
            }

            this.Properties.AddProperty(key, value);
        }

        /// <summary>
        /// Starts a VS Speaker session and raise the Start session event.
        /// </summary>
        internal void StartSession()
        {
            if (!this.IsSessionStarted)
            {
                OnSessionStarting(new EventArgs());
                this.IsSessionStarted = true;
                OnSessionStarted(new EventArgs());
            }
        }

        /// <summary>
        /// Raises the SessionStarted event
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSessionStarted(EventArgs e)
        {
            if (SessionStarted != null)
            {
                SessionStarted(this, e);
            }
        }

        /// <summary>
        /// Raises the SessionStarting event
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSessionStarting(EventArgs e)
        {
            if (SessionStarting != null)
            {
                SessionStarting(this, e);
            }
        }

        /// <summary>
        /// Ends a VS Speaker session and raise the End session event
        /// </summary>
        internal void EndSession()
        {
            if (this.IsSessionStarted)
            {
                OnSessionEnding(new EventArgs());
                this.IsSessionStarted = false;
                OnSessionEnded(new EventArgs());
            }
        }

        /// <summary>
        /// Raises the SessionEnded event
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSessionEnded(EventArgs e)
        {
            if (SessionEnded != null)
            {
                SessionEnded(this, e);
            }
        }

        /// <summary>
        /// Raises the SessionEnding event
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnSessionEnding(EventArgs e)
        {
            if (SessionEnding != null)
            {
                SessionEnding(this, e);
            }
        }
    }
}